﻿using System.Collections.Concurrent;
using System.Net;
using System.Net.Security;
using System.Security.Cryptography.X509Certificates;

namespace ShareHelper.HttpHelper
{
    /// <summary>
    /// Http 请求数据 基类
    /// </summary>
    public abstract class RequestData
    {
        static RequestData()
        {
            WebRequest.DefaultWebProxy = null;//设置默认代理为空
            //Encoding.RegisterProvider(CodePagesEncodingProvider.Instance); //注册编码
            ServicePointManager.DefaultConnectionLimit = 1024; //设置http请求并发数量
            ServicePointManager.Expect100Continue = false;//禁止Post 前发送100包测试
            ServicePointManager.UseNagleAlgorithm = false; //禁止Nagle算法加快载入速度
            //Https 加密协议
            ServicePointManager.SecurityProtocol = SecurityProtocolType.Tls | SecurityProtocolType.Tls11 | SecurityProtocolType.Tls12 | SecurityProtocolType.Ssl3;
            //Http 证书处理方案
            ServicePointManager.ServerCertificateValidationCallback =
               new RemoteCertificateValidationCallback((sender, certificate, chain, errors) =>
               {
                   return true;
               });
        }

        /// <summary>
        /// 创建Http 请求记录数据
        /// </summary>
        /// <param name="Headers"></param>
        /// <param name="cookie"></param>
        public RequestData(ConcurrentDictionary<string, string> Headers, CookieEasy cookie)
        {
            DefaultHeaders = Headers;
            Cookie = cookie;
        }

        #region 证书设置

        /// <summary>
        /// 请求使用证书
        /// </summary>
        public X509Certificate Certificate { get; set; }

        /// <summary>
        /// 创建一个请求时的证书
        /// </summary>
        /// <param name="Path">证书绝对路径 如果为空 清空证书</param>
        /// <param name="password">不为空 创建一个带密码的证书</param>
        public void SetCertificate(string Path = null, string password = null)
        {
            if (string.IsNullOrWhiteSpace(Path)) Certificate = null;//路径为空清除证书
            else if (string.IsNullOrWhiteSpace(password)) Certificate = new X509Certificate(Path);
            else Certificate = new X509Certificate(Path, password);//创建一个带密码的证书
        }

        #endregion 证书设置

        #region Cookies 处理

        /// <summary>
        /// 是否处理cookie 默认 真
        /// </summary>
        public bool AutoCookies { get; set; } = true;

        /// <summary>
        /// Cookie 处理对象
        /// </summary>
        public CookieEasy Cookie { get; }

        #endregion Cookies 处理

        #region 重定向设置

        /// <summary>
        /// 如果处理程序应跟随重定向响应, 则为true否则false为。 默认值为 false。
        /// </summary>
        public bool NeverRedirect { get; set; } = false;

        /// <summary>
        /// 自动递归重定向计次 默认一次访问最多20次重定向
        /// </summary>
        public int RedirectIndex { get; set; } = 20;

        #endregion 重定向设置

        #region 超时设置

        /// <summary>
        /// 与服务器 上传 或 下载 超时时间 默认五分钟
        /// </summary>
        public int ReadWriteTimeout { get; set; } = 1000 * 60 * 5;

        /// <summary>
        ///   获取或设置一个值，该值指示是否与 Internet 资源建立持续型连接。 默认为 true
        /// </summary>
        public bool KeepAlive { get; set; } = true;

        /// <summary>
        /// 超时时间 默认60秒 单位毫秒 与服务器建立通讯连接超时
        /// </summary>
        public int Timeout { get; set; } = 1000 * 60;

        #endregion 超时设置

        #region 代理设置

        /// <summary>
        /// 代理对象
        /// </summary>
        public IWebProxy UserProxy { get; set; }

        /// <summary>
        /// 设置或取消代理 （设置后一直有效）
        /// </summary>
        /// <param name="proxy">空=取消代理  Proxy="127.0.0.1:8080”</param>
        /// <param name="userName">代理账号</param>
        /// <param name="password">代理密码</param>
        /// <returns></returns>
        public void SetProxy(string proxy = null, string userName = null, string password = null)
        {
            //判断代理是否为空  如为空 赋值为 null 请求禁止代理
            if (string.IsNullOrEmpty(proxy)) UserProxy = null;
            else
            {//如不为空 创建 Webproxy 代理对象
                UserProxy = new WebProxy(proxy);
                //判断代理 账号密码是否为空 不为空 创建 账号密码 对象
                if (!string.IsNullOrEmpty(userName) && !string.IsNullOrEmpty(password))
                    UserProxy.Credentials = new NetworkCredential(userName, password);
            }
        }

        #endregion 代理设置

        #region 请求头 Header 相关设置

        /// <summary>
        /// 快速设置Accept协议头信息 （必须在Open后使用）
        /// </summary>
        public string Accept
        {
            get { return GetHeader(HeaderKey.Accept); }
            set { SetRequestHeader(HeaderKey.Accept, value); }
        }

        /// <summary>
        ///   提交数据 方式 /类型
        /// </summary>
        public string ContentType
        {
            get { return GetHeader(HeaderKey.ContentType); }
            set { SetRequestHeader(HeaderKey.ContentType, value); }
        }

        /// <summary>
        /// 快速设置Accept-Language协议头信息 （必须在Open后使用）
        /// </summary>
        public string AcceptLanguage
        {
            get { return GetHeader(HeaderKey.AcceptLanguage); }
            set { SetRequestHeader(HeaderKey.AcceptLanguage, value); }
        }

        /// <summary>
        /// 设置自动补全模式 此模式开启后会自动帮你补全必要的协议头（目前只包括User-Agent,Accept,Accept-Encoding,Accept-Language,Cache-Control,Content-Type） （设置后一直有效） （必须在Open前使用）
        /// </summary>
        public bool Auto { get; set; } = true;

        /// <summary>
        /// 固定的 RequestHeader
        /// </summary>
        public ConcurrentDictionary<string, string> DefaultHeaders { get; }

        /// <summary>
        /// 快速设置多重伪造IP协议头（包括：X-Forwarded-For,CLIENT_IP,VIA,REMOTE_ADDR） （必须在Open后使用）
        /// </summary>
        public string FakeIP
        {
            get { return GetHeader(HeaderKey.XForwardedFor); }
            set
            {
                SetRequestHeader(HeaderKey.XForwardedFor, value);
                SetRequestHeader(HeaderKey.CLIENT_IP, value);
                SetRequestHeader(HeaderKey.VIA, value);
                SetRequestHeader(HeaderKey.REMOTE_ADDR, value);
            }
        }

        /// <summary>
        /// 快速设置Origin出身协议头信息 （必须在Open后使用）
        /// </summary>
        public string Origin
        {
            get { return GetHeader(HeaderKey.Origin); }
            set { SetRequestHeader(HeaderKey.Origin, value); }
        }

        /// <summary>
        /// 快速设置Referer来路协议头信息 （必须在Open后使用）
        /// </summary>
        public string Referer
        {
            get { return GetHeader(HeaderKey.Referer); }
            set { SetRequestHeader(HeaderKey.Referer, value); }
        }

        /// <summary>
        /// 快速设置User-Agent浏览器协议头信息 （必须在Open后使用）
        /// </summary>
        public string UserAgernt
        {
            get { return GetHeader(HeaderKey.UserAgent); }

            set { SetRequestHeader(HeaderKey.UserAgent, value); }
        }

        /// <summary>
        /// 快速设置x-requested-with 协议头为 XMLHttpRequest （必须在Open后使用）
        /// </summary>
        public string Xrequestedwith
        {
            get { return GetHeader(HeaderKey.Xrequestedwith); }

            set { SetRequestHeader(HeaderKey.Xrequestedwith, value); }
        }

        /// <summary>
        /// 获取 Header 存在返回 内容 不存在返回空文本
        /// </summary>
        /// <param name="header">header Name</param>
        /// <returns>string Header value</returns>
        public abstract string GetHeader(string header);

        /// <summary>
        /// 添加或替换HTTP协议头（必须在Open后使用）
        /// </summary>
        /// <param name="header">协议头名称</param>
        /// <param name="value">协议头内容 空文本为删除此协议头</param>
        public abstract void SetRequestHeader(string header, string value = null);

        #endregion 请求头 Header 相关设置
    }
}